package com.wuze.cloud.service.impl;

import com.wuze.cloud.adapter.SysFolderAdapter;
import com.wuze.cloud.adapter.SysShareAdapter;
import com.wuze.cloud.context.UserContext;
import com.wuze.cloud.dao.*;
import com.wuze.cloud.exception.SysGlobalException;
import com.wuze.cloud.pojo.*;
import com.wuze.cloud.request.*;
import com.wuze.cloud.response.SysFolderResponse;
import com.wuze.cloud.response.SysShareFolderResponse;
import com.wuze.cloud.response.SysShareResponse;
import com.wuze.cloud.service.SysFolderService;
import com.wuze.cloud.service.SysShareService;
import com.wuze.cloud.util.SnowFlakeIdWorker;
import com.wuze.cloud.util.UuidUtil;
import org.assertj.core.util.Lists;
import org.assertj.core.util.Sets;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

import static com.wuze.cloud.enums.SysBooleanEnum.FALSE;
import static com.wuze.cloud.enums.SysBooleanEnum.TRUE;
import static com.wuze.cloud.enums.SysFileTypeEnum.*;
import static com.wuze.cloud.enums.SysGlobalExceptionEnum.*;
import static com.wuze.cloud.enums.SysStateEnum.CREATE;

/**
 * @Author wuze
 * @Date 2023/5/8 10:15
 * @ClassName: SysShareServiceImpl
 * @Description: TODO
 */
@Service
public class SysShareServiceImpl implements SysShareService {

    @Autowired
    private SysFolderDao folderDao;

    @Autowired
    private SysShareDao shareDao;

    @Autowired
    private SysShareAdapter shareAdapter;

    @Autowired
    private SysFolderAdapter folderAdapter;

    @Autowired
    private SysFolderService folderService;

    @Autowired
    private SysFolderRelationDao folderRelationDao;

    @Autowired
    private SysFileDao fileDao;

    @Autowired
    private SysStorageDao storageDao;

    /**
     * 分页查询共享文件及
     * @param query
     * @return
     */
    @Override
    public SysShareResponse findByPage(SysShareQuery query) {
        SysUserDO user = UserContext.getUser();
        SysShareResponse response = new SysShareResponse();
        query.setUserId(user.getId());
        Integer total = shareDao.count(query);
        if (total == 0) {
            response.setTotal(total);
            response.setShares(Lists.newArrayList());
            return response;
        }
        List<SysShareDO> shares = shareDao.findByPage(query);
        response.setShares(shareAdapter.buildSysShareVOList(shares));
        response.setTotal(total);
        return response;
    }

    /**
     *根据共享ID获取共享文件夹信息
     * @param query
     * @return
     */
    @Override
    public SysShareFolderResponse getShareFolder(SysShareFolderQuery query) {
        SysShareDO share = shareDao.findByShareId(query.getShareId(), query.getPassword());
        if (Objects.isNull(share)) {
            throw new SysGlobalException(SHARE_ID_NOT_FIND.getCode(), SHARE_ID_NOT_FIND.getMsg());
        }

        if (share.getForever().equals(TRUE.getCode())) {
            return folderAdapter.buildSysShareFolderResponse(share.getFolderId(), CREATE.name());
        }
        Date date = new Date();
        if (date.before(share.getStartDate()) || date.after(share.getDeadlineDate())) {
            throw new SysGlobalException(SHARE_DATA_ERR.getCode(), SHARE_DATA_ERR.getMsg());
        }
        return folderAdapter.buildSysShareFolderResponse(share.getFolderId(), CREATE.name());
    }

    /**
     * 分页查询共享文件信息
     * @param query
     * @return
     */
    @Override
    public SysFolderResponse findShareByPage(SysShareFolderQuery query) {
        SysShareDO share = shareDao.findByShareId(query.getShareId(), query.getPassword());
        if (Objects.isNull(share)) {
            throw new SysGlobalException(SHARE_ID_NOT_FIND.getCode(), SHARE_ID_NOT_FIND.getMsg());
        }
        SysFolderQuery folderQuery = new SysFolderQuery();
        folderQuery.setId(query.getFolderId());
        folderQuery.setUserId(share.getUserId());
        folderQuery.setState(0);

        return folderService.findByPage(folderQuery);
    }

    /**
     * 创建共享文件夹
     * @param query
     */
    @Override
    public void createShare(SysCreateShareQuery query) {

        SysUserDO user = UserContext.getUser();
        //校验请求
        verifyCreateQuery(query);
        //构建共享实体DO
        SysShareDO shareDO = shareAdapter.buildSysShareDO(query);
        //保存共享文件夹记录
        shareDao.add(shareDO);

    }




    /**
     * 校验创建共享请求
     * @param query
     */
    private void verifyCreateQuery(SysCreateShareQuery query) {

        SysFolderDO folder = folderDao.findById(query.getFolderId());

        if (Objects.isNull(folder)) {
            throw new SysGlobalException(FILE_NOT_FOUND.getCode(), FILE_NOT_FOUND.getMsg());
        }
        if (!folder.getState().equals(CREATE.name())) {
            throw new SysGlobalException(FILE_NOT_FOUND.getCode(), FILE_NOT_FOUND.getMsg());
        }
        if (query.getForever().equals(FALSE.getCode())
                && (query.getDeadlineDate() == null || query.getStartDate() == null)) {
            throw new SysGlobalException(DATA_ERR.getCode(), DATA_ERR.getMsg());
        }

    }

    /**
     * 修改共享文件夹
     * @param query
     */
    @Override
    public void updateShare(SysUpdateShareQuery query) {
        //校验请求
        SysShareDO share = verifyUpdateQuery(query);
        //修改数据
        if (query.getForever().equals(TRUE.getCode())) {
            query.setStartDate(null);
            query.setDeadlineDate(null);
        }
        share.setForever(query.getForever());
        share.setStartDate(query.getStartDate());
        share.setDeadlineDate(query.getDeadlineDate());
        share.setPassword(query.getPassword());
        shareDao.updateById(share);

    }


    /**
     * 校验修改共享请求
     *
     * @param query
     */
    private SysShareDO verifyUpdateQuery(SysUpdateShareQuery query) {
        SysUserDO user = UserContext.getUser();
        SysShareDO share = shareDao.findById(query.getId(), user.getId());
        if (Objects.isNull(share)) {
            throw new SysGlobalException(NOT_FIND.getCode(), NOT_FIND.getMsg());
        }
        return share;
    }

    /**
     * 删除共享文件夹
     * @param query
     */
    @Override
    public void deleteShare(SysDeleteShareQuery query) {
        //校验删除请求
        verifyDeleteQuery(query);
        //执行删除
        shareDao.deleteByIds(query.getIds());
    }

    /**
     * 校验删除共享文件夹请求
     * @param query
     */
    private void verifyDeleteQuery(SysDeleteShareQuery query) {
        if (CollectionUtils.isEmpty(query.getIds())) {
            throw new SysGlobalException(DATA_ERR.getCode(), DATA_ERR.getMsg());
        }
    }

    /**
     * 转存共享文件
     * @param query
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveShare(SysShareSaveQuery query) {
        //校验请求
        verifyShareSaveQuery(query);
        String uuid = UuidUtil.getShortUuid() + "_";
        //转存文件
        if (!CollectionUtils.isEmpty(query.getFileIds())) {
            saveShareFiles(query, uuid);
        }
        //转存文件夹
        if (!CollectionUtils.isEmpty(query.getFolderIds())) {
            saveShareFolders(query, uuid);
        }

    }

    /**
     * 校验转存请求
     * @param query 转存请求实体
     */
    private void verifyShareSaveQuery(SysShareSaveQuery query) {
        SysUserDO user = UserContext.getUser();
        //获取共享文件夹记录
        SysShareDO share = shareDao.findByShareId(query.getShareId(), query.getPassword());
        query.setShareUserId(share.getUserId());
        if(user.getId().equals(share.getUserId())){
            throw new SysGlobalException(SHARE_ERR.getCode(), SHARE_ERR.getMsg());
        }
    }

    /**
     * 转存共享文件
     * @param query
     * @param uuid
     */
    private void saveShareFiles(SysShareSaveQuery query, String uuid) {
        SysUserDO user = UserContext.getUser();
        SysStorageDO storage = storageDao.findByUserId(user.getId());
        List<SysFileDO> files = fileDao.findByIds(Sets.newHashSet(query.getFileIds()), CREATE.name());
        files.forEach(file -> {
            //添加文件表数据
            file.setId(SnowFlakeIdWorker.nextId());
            file.setFolderId(query.getFolderId());
            file.setUserId(user.getId());
            file.setFileName(uuid + file.getFileName());
            fileDao.save(file);
            //添加文件关系表数据
            SysFolderRelationDO relation = new SysFolderRelationDO();
            relation.setId(SnowFlakeIdWorker.nextId());
            relation.setChildId(file.getId());
            relation.setPid(query.getFolderId());
            relation.setType(file.getType());
            relation.setState(CREATE.name());
            relation.setChildName(uuid + file.getFileName());
            relation.setUserId(user.getId());
            folderRelationDao.add(relation);

            Long size = file.getSize();
            String type = file.getType();
            storage.setCurrSize(storage.getCurrSize() + size);
            if (type.equals(DOCUMENT_FILE.name())) {
                storage.setDocumentSize(storage.getDocumentSize() + size);
            } else if (type.equals(VIDEO_FILE.name())) {
                storage.setVideoSize(storage.getVideoSize() + size);
            } else if (type.equals(IMAGE_FILE.name())) {
                storage.setImageSize(storage.getImageSize() + size);
            } else if (type.equals(OTHER_FILE.name())) {
                storage.setOrtherSize(storage.getOrtherSize() + size);
            }
        });
        if(storage.getCurrSize()>storage.getMaxSize()){
            throw new SysGlobalException(SPACE_NOT_ENOUGH.getCode(),SPACE_NOT_ENOUGH.getMsg());
        }
        storageDao.update(storage);
    }

    /**
     * 转存共享文件夹
     * @param query
     * @param uuid
     */
    private void saveShareFolders(SysShareSaveQuery query, String uuid) {
        SysUserDO user = UserContext.getUser();
        List<Long> folderIds = query.getFolderIds();
        folderIds.forEach(folderId -> {
            //添加文件夹数据表
            SysFolderDO folder = folderDao.findById(folderId);
            SysFolderDO newFolder = new SysFolderDO();
            BeanUtils.copyProperties(folder, newFolder);
            newFolder.setId(SnowFlakeIdWorker.nextId());
            newFolder.setFolderName(uuid + newFolder.getFolderName());
            newFolder.setUserId(user.getId());
            newFolder.setPid(query.getFolderId());
            folderDao.save(newFolder);
            //添加文件关系表数据
            SysFolderRelationDO relation = new SysFolderRelationDO();
            relation.setId(SnowFlakeIdWorker.nextId());
            relation.setChildId(newFolder.getId());
            relation.setPid(query.getFolderId());
            relation.setType(FOLDER_FILE.name());
            relation.setState(CREATE.name());
            relation.setChildName(uuid + newFolder.getFolderName());
            relation.setUserId(user.getId());
            folderRelationDao.add(relation);
            //添加子文件表
            List<SysFileDO> files = fileDao.findByFolderIds(Lists.newArrayList(folderId), query.getShareUserId(), CREATE.name());
            if (!CollectionUtils.isEmpty(files)) {
                List<Long> fileIds = files.stream().map(SysFileDO::getId).collect(Collectors.toList());
                SysShareSaveQuery newQuery = new SysShareSaveQuery();
                BeanUtils.copyProperties(query, newQuery);
                newQuery.setFileIds(fileIds);
                newQuery.setFolderId(newFolder.getId());
                saveShareFiles(newQuery, "");
            }

            //添加子文件夹表
            List<SysFolderDO> folders = folderDao.findByPid(folderId, CREATE.name());
            if (!CollectionUtils.isEmpty(folders)) {
                List<Long> chileIds = folders.stream().map(SysFolderDO::getId).collect(Collectors.toList());
                SysShareSaveQuery newQuery = new SysShareSaveQuery();
                BeanUtils.copyProperties(query, newQuery);
                newQuery.setFolderIds(chileIds);
                newQuery.setFolderId(newFolder.getId());
                saveShareFolders(newQuery, "");
            }

        });
    }

    /**
     * 构建共享的所有文件id
     *
     * @param query
     * @return
     */
    private Set<Long> getShareFileIds(SysShareSaveQuery query) {
        SysUserDO user = UserContext.getUser();
        Set<Long> ids = new HashSet<>(query.getFileIds());
        if (!CollectionUtils.isEmpty(query.getFolderIds())) {
            List<Long> list = getFolderIdsByFolderIds(query.getFolderIds());
            List<SysFileDO> files = fileDao.findByFolderIds(list, user.getId(), CREATE.name());
            ids.addAll(files.stream().map(SysFileDO::getId).collect(Collectors.toSet()));
        }
        return ids;
    }

    /**
     * 获取文件夹及所有子文件夹id
     *
     * @param folderIds
     * @return
     */
    private List<Long> getFolderIdsByFolderIds(List<Long> folderIds) {
        List<Long> result = Lists.newArrayList();
        if (CollectionUtils.isEmpty(folderIds)) {
            return result;
        }
        result.addAll(folderIds);
        List<SysFolderRelationDO> relationDOS = folderRelationDao.findByPids(folderIds, FOLDER_FILE.name(), CREATE.name());
        if (CollectionUtils.isEmpty(relationDOS)) {
            return result;
        }
        List<Long> ids = relationDOS.stream().map(SysFolderRelationDO::getChildId).collect(Collectors.toList());
        result.addAll(getFolderIdsByFolderIds(ids));
        return result;
    }

}
